import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';

class SMDioManager {
  static Dio? _dio;
  factory SMDioManager() => _instance;
  static final SMDioManager _instance = SMDioManager._internal();

  /// 获取dio
  Dio? get dio => _dio;

  /// 初始化
  SMDioManager._internal() {
    _dio ??= Dio();
  }

  /// 设置代理
  void setProxy({String? address = ''}) {
    _dio?.httpClientAdapter = IOHttpClientAdapter(createHttpClient: () {
      final HttpClient client = HttpClient();
      client.findProxy = (uri) {
        if (address!.isNotEmpty) {
          return 'PROXY $address';
        } else {
          return 'DIRECT';
        }
      };
      return client;
    });
  }

  /// 添加拦截器
  void addInterceptor({required List<Interceptor> elements}) =>
      _dio?.interceptors.addAll(elements);

  /// get 方法
  static Future<dynamic> get(
      {required String path,
      Map<String, dynamic>? queryParameters,
      Options? options,
      ProgressCallback? onReceiveProgress}) async {
    Response? response = await _dio?.get(path,
        queryParameters: queryParameters,
        options: options,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }

  /// post 方法
  static Future<dynamic> post(
      {required String path,
      dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress}) async {
    Response? response = await _dio?.post(path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }

  /// put 方法
  static Future<dynamic> put(
      {required String path,
      dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress}) async {
    Response? response = await _dio?.put(path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }

  /// head 方法
  static Future<dynamic> head(
      {required String path,
      dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? options}) async {
    Response? response = await _dio?.head(path,
        data: data, queryParameters: queryParameters, options: options);
    return response?.data;
  }

  /// delete 方法
  static Future<dynamic> delete(
      {required String path,
      dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? options}) async {
    Response? response = await _dio?.delete(path,
        data: data, queryParameters: queryParameters, options: options);
    return response?.data;
  }

  /// patch 方法
  static Future<dynamic> patch(
      {required String path,
      dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress}) async {
    Response? response = await _dio?.patch(path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }

  /// download 方法
  static Future<dynamic> download(
      {required String urlPath,
      required String savePath,
      Map<String, dynamic>? queryParameters,
      dynamic data,
      Options? options,
      ProgressCallback? onReceiveProgress}) async {
    Response? response = await _dio?.download(urlPath, savePath,
        queryParameters: queryParameters,
        data: data,
        options: options,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }

  /// upload 方法 (eg:formData可以是字符串路径,也可以是文件的二进制数据data)
  static Future<dynamic> upload(
      {required String path,
      dynamic formData,
      Map<String, dynamic>? queryParameters,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress}) async {
    FormData uploadFormData;
    switch (formData.runtimeType) {
      case String:
        uploadFormData = FormData.fromMap({
          'file': MultipartFile.fromFileSync(
            formData,
            filename: '${DateTime.now()}.png',
          )
        });
        break;

      case List:
        uploadFormData = FormData.fromMap({
          'file': MultipartFile.fromBytes(
            formData,
            filename: '${DateTime.now()}.png',
          )
        });
        break;

      default:
        uploadFormData = FormData.fromMap({});
        break;
    }

    Response? response = await _dio?.post(path,
        data: uploadFormData,
        queryParameters: queryParameters,
        options: options,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
    return response?.data;
  }
}
